/***************************************************************************************

***************************************************************************************/


/*
*************************************************************************************
* File name: image.c
* Function: Decode a Slice
*
*************************************************************************************
*/


#include "contributors.h"

#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <sys/timeb.h>
#include <string.h>
#include <assert.h>
#ifdef WIN32
#include <IO.H>
#include <STDIO.H>
#endif

#include "global.h"
#include "header.h"
#include "annexb.h"
#include "vlc.h"
#include "memalloc.h"
#include "bbv.h" 

//!EDIT START <added by  AEC
#include "context_ini.h"    
#include "AEC.h"   
#include "biaridecod.h"
#include "pixel.h"
//!EDIT end <added by  AEC

void copy2buffer(img_params *img, inp_params *inp,int bot);
void replace2buffer(img_params *img, inp_params *inp,int bot);
void DecideMvRange();	// ITM

BbvBuffer_t *pBbv = NULL; 


unsigned char *temp_slice_buf;
int first_slice_length;
int first_slice_startpos;

extern StatBits *StatBitsPtr;	

/*
*************************************************************************
* Function:decodes one I- or P-frame
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
int decode_one_frame(img_params *img,inp_params *inp, snr_par *snr)
{
	int current_header;

	time_t ltime1;                  // for time measurement
	time_t ltime2;

	struct timeb tstruct1;
	struct timeb tstruct2;

	int tmp_time;                   // time used by decoding the last frame

	float framerate[8]={24000/1001,24,25,30000/1001,30,50,60000/1001,60};  //ITM_r2

	ftime (&tstruct1);              // start time ms
	time( &ltime1 );                // start time s

	img->current_mb_nr = -4711; // initialized to an impossible value for debugging -- correct value is taken from slice header

	if (input->check_BBV_flag && img->number && pBbv)
	{
		pBbv->frame_code_bits = 0;
	}
	current_header = Header();

	DecideMvRange();  //ITM

	if (current_header == EOS)
		return EOS;

	// if the size is not the integer times of B
	if (horizontal_size% MB_SIZE != 0)
	{
		img->auto_crop_right = MB_SIZE-(horizontal_size % MB_SIZE);
	}
	else
	{
		img->auto_crop_right=0;
	}
	if (!progressive_sequence) 
	{
		if (vertical_size % (2*MB_SIZE) != 0)
		{
			img->auto_crop_bottom = (2*MB_SIZE)-(vertical_size % (2*MB_SIZE));
		}
		else
		{
			img->auto_crop_bottom=0;
		}
	}
	else              
	{
		if (vertical_size % MB_SIZE != 0)   
		{
			img->auto_crop_bottom = MB_SIZE-(vertical_size % MB_SIZE);
		}
		else
		{
			img->auto_crop_bottom=0;
		}
	}
	if((img->auto_crop_bottom != 0) || (img->auto_crop_right != 0))
	{
		// Re-init parameters (NOTE: need to do before init_frame)
		img->width          = (horizontal_size+img->auto_crop_right);
		img->height         = (vertical_size+img->auto_crop_bottom);
		img->width_cr       = (img->width>>1);
		img->height_cr      = (img->height>>1);
		img->iStride        = img->width + 2*IMG_PAD_SIZE;
		img->iStrideC       = img->iStride >> 1;
		img->PicWidthInMbs  = img->width/MB_SIZE;
		img->PicHeightInMbs = img->height/MB_SIZE;
		img->PicSizeInMbs   = img->PicWidthInMbs * img->PicHeightInMbs;
		img->max_mb_nr      =(img->width * img->height) / (MB_SIZE * MB_SIZE);
		assert(img->PicSizeInMbs == img->max_mb_nr); // after crop, these two variables are always same.
	}

	img->current_mb_nr = 0;

	init_frame(img, inp);

	img->types = img->type;   

	if((img->type==P_IMG)&&((pre_dec_img_type == I_IMG)||(pre_dec_img_type==B_IMG)))
		b_pre_dec_intra_img=TRUE;
	else if ((img->type==P_IMG)&&(pre_dec_img_type==P_IMG))
		b_pre_dec_intra_img=FALSE; 

	pre_dec_img_type=img->type;	
	if(img->type!=B_IMG)
	{		
		pre_img_type  = img->type;		
		pre_img_types = img->types;		
	}

	picture_data(img);

	img->height = (vertical_size+img->auto_crop_bottom);
	img->height_cr = /*vertical_size*/ img->height/2;	
	img->PicWidthInMbs  = img->width/MB_SIZE;
	img->PicHeightInMbs = img->height/MB_SIZE;
	img->PicSizeInMbs   = img->PicWidthInMbs * img->PicHeightInMbs;

	frame_postprocessing(img);

	if (img->type==B_IMG) {
		if (p_ref)
			find_snr(snr,img,p_ref, img_prev);      // if ref sequence exist
	}

	ftime (&tstruct2);    // end time ms

	time( &ltime2 );                                // end time sec
	tmp_time=(int)((ltime2*1000+tstruct2.millitm) - (ltime1*1000+tstruct1.millitm));
	tot_time=tot_time + tmp_time;

	//ITM_r2
	StatBitsPtr->curr_frame_bits = StatBitsPtr->curr_frame_bits*8 + StatBitsPtr->emulate_bits - StatBitsPtr->last_unit_bits;
	StatBitsPtr->bitrate += StatBitsPtr->curr_frame_bits;
	StatBitsPtr->coded_pic_num++;
	if( (int)(StatBitsPtr->coded_pic_num - (StatBitsPtr->time_s+1)*framerate[frame_rate_code-1] + 0.5) == 0 )
	{
		StatBitsPtr->total_bitrate[StatBitsPtr->time_s++] = StatBitsPtr->bitrate;
		CheckBitrate(StatBitsPtr->bitrate,StatBitsPtr->time_s);
		StatBitsPtr->bitrate = 0;
	}

	if (img->type!=B_IMG) {
		pre_tmp_time = tmp_time;
		pre_img_tr   = img->tr;
		pre_img_qp   = img->qp;
		StatBitsPtr->prev_frame_bits = StatBitsPtr->curr_frame_bits; 
		StatBitsPtr->prev_emulate_bits = StatBitsPtr->emulate_bits;  
	}	 

	if(input->ref_pic_order) {    //ref order
		if(img->type == I_IMG) // I picture
			fprintf(stdout,"%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\n",
			dec_ref_num, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time);
		else if(img->type == P_IMG) // P pictures
		{
			if (img->types == I_IMG)
				fprintf(stdout,"%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\n",
				dec_ref_num, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time);  
			else
				fprintf(stdout,"%3d(P)  %3d %5d %7.4f %7.4f %7.4f %5d\n",
				dec_ref_num, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time);
		}
		else // B pictures
			fprintf(stdout,"%3d(B)  %3d %5d %7.4f %7.4f %7.4f %5d\n",
			dec_ref_num, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time);
	}
	else if(img->type==B_IMG)
		fprintf(stdout,"%3d(B)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\n",
		FrameNum, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time,"FRM",StatBitsPtr->curr_frame_bits,StatBitsPtr->emulate_bits);

	if (input->check_BBV_flag)
		pBbv->frame_code_bits        = StatBitsPtr->curr_frame_bits;     
	StatBitsPtr->curr_frame_bits = 0;								
	StatBitsPtr->emulate_bits    = 0;								
	StatBitsPtr->last_unit_bits  = 0;								

	fflush(stdout);

	if(img->type==B_IMG)
		report_frame(snr,tmp_time);

	if(img->type == I_IMG || img->type == P_IMG) // I or P pictures
	{
		copy_Pframe(img, img_prev);

		Update_Picture_Buffers();
	}
	else if (input->output_dec_pic)  // output_dec_pic // B pictures
		write_frame(img, p_out);  // write image to output YUV file 

	if (input->check_BBV_flag)
	{    
		update_bbv(pBbv, pBbv->frame_code_bits);
	}


	if(img->type == I_IMG || img->type == P_IMG)   // I or P pictures
		img->number++;
	else
		Bframe_ctr++;    // B pictures

	return (SOP);
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
void report_frame(snr_par *snr,int tmp_time)
{
	FILE *file;
	file = fopen("stat.dat","at");

	if(img->type == I_IMG) // I picture
		fprintf(file,"%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s\n",
		FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time,"FRM"); 

	else if(img->type == P_IMG) // P pictures
		fprintf(file,"%3d(P)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s\n",
		FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time,"FRM");

	else // B pictures
		fprintf(file,"%3d(B)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s\n",
		FrameNum, img->tr, img->qp,snr->snr_y,snr->snr_u,snr->snr_v,tmp_time,"FRM");

	FrameNum++;	

	fclose(file);
}
/* ---------------------------------------------------------------------------
* Function   : calculate the MAD of 2 frames
* Parameters :
*      [in ] : width      - width   of frame
*            : height     - height  of frame
*            : rec        - pointer to reconstructed frame buffer
*            : rec_stride - stride  of reconstructed frame
*            : dst        - pointer to decoded frame buffer
*            : dst_stride - stride  of decoded frame
*      [out] : none
* Return     : mad of 2 frames
* ---------------------------------------------------------------------------
*/
static __inline int
	cal_mad(int width, int height, unsigned char *rec, int rec_stride, unsigned char *dst, int dst_stride)
{
	int is_error = 0;
	int d = 0;
	int i, j, t;

	for (j = 0; j < height; j++) {
		for (i = 0; i < width; i++) {
			t = dst[i] - rec[i];
			d += t * t;
		}
		rec += rec_stride;
		dst += dst_stride;
	}

	if (is_error) {
		fprintf(stderr, "\n");
	}

	return d;
}

/* ---------------------------------------------------------------------------
* Function   : calculate and output the psnr (only for YUV 4:2:0)
* Parameters :
*      [in ] : rec    - pointer to buffer of reconstructed picture
*            : dst    - pointer to buffer of decoded picture
*            : width  - width  of picture
*            : height - height of picture
*      [out] : none
* Return     : void
* ---------------------------------------------------------------------------
*/
static void cal_psnr(snr_par * snr, unsigned char *rec, unsigned char *dst, int width, int height)
{
	int stride = width;         /* stride of frame/field  (luma) */
	int size_l = width * height;/* size   of frame/field  (luma) */
	int diff;                   /* difference between decoded and reconstructed picture */
	unsigned char *p1;          /* pointer to buffer of reconstructed picture */
	unsigned char *p2;          /* pointer to buffer of decoded picture */
	float fpsnr;

	/* Y */
	p1 = rec;
	p2 = dst;
	diff = cal_mad(width, height, p1, stride, p2, stride);
	if (diff == 0) {
		fpsnr = 0.0f;
	}
	else {
		fpsnr = (float)(10 * log10(65025.0F * size_l / diff));
	}
	snr->snr_y = fpsnr;
	snr->snr_sum_y += fpsnr;

	width >>= 1;               /* width  of frame/field  (chroma) */
	height >>= 1;               /* height of frame/field  (chroma, with padding) */
	stride >>= 1;               /* stride of frame/field  (chroma) */

	/* U */
	p1 += size_l;
	p2 += size_l;
	diff = cal_mad(width, height, p1, stride, p2, stride);
	if (diff == 0) {
		fpsnr = 0.0f;
	} else {
		fpsnr = (float)(10 * log10(65025.0F * size_l / diff));
	}
	snr->snr_u = fpsnr;
	snr->snr_sum_u += fpsnr;

	/* V */
	p1 += size_l / 4;
	p2 += size_l / 4;
	diff = cal_mad(width, height, p1, stride, p2, stride);
	if (diff == 0) {
		fpsnr = 0.0f;
	} else {
		fpsnr = (float)(10 * log10(65025.0F * size_l / diff));
	}
	snr->snr_v = fpsnr;
	snr->snr_sum_v += fpsnr;
}

void find_snr(snr_par *snr, img_params *img, FILE *p_ref, uchar_t *pic_dec_prev)
{
	int i,j;
	int  status;

	// find the real width and height of image
	int img_org_width = (img->width-img->auto_crop_right);
	int img_org_height = (img->height-img->auto_crop_bottom);
	int img_org_widthc = img_org_width >> 1;
	int img_org_heightc = img_org_height >> 1; 

	const unsigned int  bytes_y = img_org_width * img_org_height;
	const unsigned int  bytes_uv = img_org_widthc * img_org_heightc;
	const int framesize_in_bytes = bytes_y + 2*bytes_uv;
	
	uchar_t *dec_buf = (uchar_t *)malloc(framesize_in_bytes);
	uchar_t *out_buf = (uchar_t *)malloc(framesize_in_bytes);
	uchar_t *out_buf_bak = out_buf;

	if(img->type==B_IMG && !eos || input->ref_pic_order)	{
		for(j = 0; j < img_org_height; j++){
			for(i = 0; i < img_org_width; i++){
				*out_buf++ = imgY_rec[j*img->iStride+i];
			}
		}
		for(j = 0; j < img_org_heightc; j++){
			for(i = 0; i < img_org_widthc; i++){
				*out_buf++ = imgU_rec[j*img->iStrideC+i];
			}
		}
		for(j = 0; j < img_org_heightc; j++){
			for(i = 0; i < img_org_widthc; i++){
				*out_buf++ = imgV_rec[j*img->iStrideC+i];
			}
		}
		out_buf -= framesize_in_bytes;
	}
	else{
		out_buf = pic_dec_prev;
	}
	
	if(RefPicExist)
	{
		if(!input->ref_pic_order) // go to the position of corresponding frame in decoding yuv file
			status = fseek (p_ref, framesize_in_bytes * FrameNum, 0);
		else
			status = fseek (p_ref, framesize_in_bytes * dec_ref_num, 0);

		if (status != 0)	
		{
			snprintf(errortext, ET_SIZE, "Error in seeking img->tr: %d", img->tr);
			RefPicExist = 0;
		}
	}
	fread(dec_buf, img_org_width*img_org_height*3/2, 1, p_ref);
	cal_psnr(snr, dec_buf, out_buf, img_org_width, img_org_height);

	free(dec_buf);
	free(out_buf_bak);
}

/*
*************************************************************************
* Function:Reads the content of two successive startcode from the bitstream
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int Header()
{
	unsigned char *Buf;
	int startcodepos,length; 
	static unsigned long prev_pos=0 , curr_pos=0;	
	static unsigned long prev_pic=0, curr_pic=0;	

	if ((Buf = (unsigned char*)calloc (MAX_CODED_FRAME_SIZE , sizeof(char))) == NULL)
		no_mem_exit("GetAnnexbNALU: Buf");

	while (1)
	{     
		StartCodePosition = GetOneUnit(Buf,&startcodepos,&length);    

		switch(Buf[startcodepos])
		{
		case SEQUENCE_HEADER_CODE:
			if (input->check_BBV_flag && !img->new_seq_header_flag && pBbv)
			{
				stat_bbv_buffer(pBbv);
				pBbv = free_bbv_memory(pBbv);
				img->new_seq_header_flag = 1;
			}

			img->new_sequence_flag = 1; 
			SequenceHeader(Buf,startcodepos,length);

			if (input->check_BBV_flag && img->new_seq_header_flag)
			{
				pBbv = init_bbv_memory(frame_rate_code, low_delay, bbv_buffer_size, bit_rate_upper, bit_rate_lower);
				img->new_seq_header_flag = 0;
			}

			img->seq_header_indicate = 1;               
			break;
		case USER_DATA_START_CODE:
			user_data(Buf,startcodepos,length);
			break;
		case VIDEO_EDIT_CODE:
			video_edit_code_data(Buf,startcodepos,length);
			break;
		case I_PICTURE_START_CODE:
			curr_pic=prev_pos;				
			I_Picture_Header(Buf,startcodepos,length);
			calc_picture_distance(img);

			if(!img->seq_header_indicate)
			{
				img->B_discard_flag = 1;
				fprintf(stdout,"    I   %3d\t\tDIDSCARD!!\n", img->tr);
				break;
			}

			if (input->check_BBV_flag)
			{
				if (!img->new_sequence_flag)
				{
					if (0x20==profile_id && ((0xFFFF==img->last_pic_bbv_delay && 0xFFFF!=bbv_delay) || (0xFFFF!=img->last_pic_bbv_delay && 0xFFFF==bbv_delay)))
					{
						fprintf(p_sreport, "If one picture's bbv_delay is 0xFFFF, then all pictures's bbv_delay is 0xFFFF.\n");
						bbv_delay = 0xFFFF;
					}
					if (0x20!=profile_id && ((0xFFFFFF==img->last_pic_bbv_delay && 0xFFFFFF!=bbv_delay) || (0xFFFFFF!=img->last_pic_bbv_delay && 0xFFFFFF==bbv_delay)))
					{
						printf("If one picture's bbv_delay is 0xFFFFFF, then all pictures's bbv_delay is 0xFFFFFF in non JiZhun Profile.\n");
						bbv_delay = 0xFFFFFF;
					}
				}

				if ((0x20==profile_id && 0xFFFF==bbv_delay) || (0x20!=profile_id && 0xFFFFFF==bbv_delay))
				{
					pBbv->bbv_mode = 1;
				}
				else
				{
					if (img->new_sequence_flag)
					{
						pBbv->bbv_delay = (float)(bbv_delay/90000.0);
					}
					else if (pBbv->check_continue && (bbv_delay<pBbv->bbv_delay*90000*0.95 || bbv_delay>pBbv->bbv_delay*90000*1.05))
					{
						fprintf(p_sreport,"\nThe bbv_delay of frame %d should be %.3f rather than %.3f.\n", FrameNum, pBbv->bbv_delay, bbv_delay/90000.0);
					}
				}

				img->last_pic_bbv_delay = bbv_delay;
			}

			break; 
		case PB_PICTURE_START_CODE:
			curr_pic=prev_pos;		
			PB_Picture_Header(Buf,startcodepos,length);
			calc_picture_distance(img);

			if(!img->seq_header_indicate)
			{
				img->B_discard_flag = 1;
				if(img->type==P_IMG)
					fprintf(stdout,"    P   %3d\t\tDIDSCARD!!\n", img->tr);
				else
					fprintf(stdout,"    B   %3d\t\tDIDSCARD!!\n", img->tr);
				break;
			}
			if (img->seq_header_indicate==1 && img->type!=B_IMG) {
				img->B_discard_flag = 0;
			}
			if (img->type==B_IMG && img->B_discard_flag==1 && !img->no_forward_reference) {
				fprintf(stdout,"    B   %3d\t\tDIDSCARD!!\n", img->tr);
				break;
			}

			if (input->check_BBV_flag)
			{
				if (0x20==profile_id && ((0xFFFF==img->last_pic_bbv_delay && 0xFFFF!=bbv_delay) || (0xFFFF!=img->last_pic_bbv_delay && 0xFFFF==bbv_delay)))
				{
					fprintf(p_sreport, "If one picture's bbv_delay is 0xFFFF, then all pictures's bbv_delay is 0xFFFF.\n");
					bbv_delay = 0xFFFF;
				}
				if (0x20!=profile_id && ((0xFFFFFF==img->last_pic_bbv_delay && 0xFFFFFF!=bbv_delay) || (0xFFFFFF!=img->last_pic_bbv_delay && 0xFFFFFF==bbv_delay)))
				{
					printf("If one picture's bbv_delay is 0xFFFFFF, then all pictures's bbv_delay is 0xFFFFFF in non Baseline Profile.\n");
					bbv_delay = 0xFFFFFF;
				}

				if ((0x20==profile_id && 0xFFFF==bbv_delay) || (0x20!=profile_id && 0xFFFFFF==bbv_delay))
				{
					pBbv->bbv_mode = 1;
				}
				else if (pBbv->check_continue && (bbv_delay<pBbv->bbv_delay*90000*0.95 || bbv_delay>pBbv->bbv_delay*90000*1.05))
				{
					fprintf(p_sreport,"\nThe bbv_delay of frame %d should be %.3f rather than %.3f.\n", FrameNum, pBbv->bbv_delay, bbv_delay/90000.0);
				}

				img->last_pic_bbv_delay = bbv_delay;
			}

			break;  
		case SEQUENCE_END_CODE:
			img->new_sequence_flag = 1; 
			img->sequence_end_flag = 1; 
			free(Buf);
			return EOS;
			break;
		default:
			if ((Buf[startcodepos]>=SLICE_START_CODE_MIN && Buf[startcodepos]<=SLICE_START_CODE_MAX) 
				&& ((!img->seq_header_indicate) || (img->type==B_IMG && img->B_discard_flag==1 && !img->no_forward_reference))) {
					break;
			}
			else if (Buf[startcodepos]>=SLICE_START_CODE_MIN) { 
				if ((temp_slice_buf = (unsigned char*)calloc (MAX_CODED_FRAME_SIZE , sizeof(char))) == NULL)
					no_mem_exit("GetAnnexbNALU: Buf");
				first_slice_length=length;
				first_slice_startpos=startcodepos;
				memcpy(temp_slice_buf,Buf,length);
				free(Buf);
				return SOP;
			} else {
				printf("Can't find start code");
				free(Buf);
				return EOS;
			}
		}
	}

}

/*
*************************************************************************
* Function:Initializes the parameters for a new frame
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
void init_frame(img_params *img, inp_params *inp)
{
	static int first_P = TRUE;
	int i;

	nextP_tr = nextP_tr_frm;

	if (img->number == 0) // first picture
	{
		nextP_tr=prevP_tr=img->pic_distance; 
	}
	else if(img->type == I_IMG || img->type == P_IMG )
	{
		nextP_tr=img->pic_distance;   

		if(first_P) // first P picture
		{
			first_P = FALSE;
			P_interval=nextP_tr-prevP_tr; 
		}

		if (p_ref && !input->ref_pic_order) 
		{  //ref order
			find_snr(snr,img,p_ref, img_prev);      // if ref sequence exist
		}
		else
		{
			find_snr(snr,img,p_ref, img_prev);      // if ref sequence exist
		}

		if(pre_img_type == I_IMG) // I picture
		{
			if(img->new_sequence_flag == 1)
			{
				if(FrameNum!=0)
				{
					printf("min bbv_buffer_size in bitstream is %d\n", ((pminBBSsize>>14) + (pminBBSsize&0x3FFF? 1 : 0)));
					if (!pbbv_mode) 
					{
						printf("min initial bbv_delay(0) time is %.4f(s)\n", (float)pminFsize/pbitrate);
					}			
				}

				if (img->sequence_end_flag) 
				{
					img->sequence_end_flag = 0;
					fprintf(stdout, "Sequence End\n\n");
				}

				if (vec_flag)
				{
					vec_flag = 0;
					fprintf(stdout, "Video Edit Code\n");
				}

				fprintf(stdout, "Sequence Header\n");
				img->new_sequence_flag = 0;
			}
			if(!input->ref_pic_order)  //ref order
				fprintf(stdout,"%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\n",
				FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time,"FRM",StatBitsPtr->prev_frame_bits,StatBitsPtr->prev_emulate_bits);
		}
		else if(pre_img_type == P_IMG) // P pictures
		{
			if (pre_img_types == I_IMG)
			{
				if(img->new_sequence_flag == 1)
				{
					if(FrameNum!=0)
					{
						printf("min bbv_buffer_size in bitstream is %d\n", ((pminBBSsize>>14) + (pminBBSsize&0x3FFF? 1 : 0))); // ITM_r1   
						if (!pbbv_mode) 
						{
							printf("min initial bbv_delay(0) time is %.4f(s)\n", (float)pminFsize/pbitrate);
						}
					}

					if (img->sequence_end_flag) 
					{
						img->sequence_end_flag = 0;
						fprintf(stdout, "Sequence End\n\n");
					} 

					if (vec_flag)
					{
						vec_flag = 0;
						fprintf(stdout, "Video Edit Code\n");
					}

					fprintf(stdout, "Sequence Header\n");
					img->new_sequence_flag = 0;
				}
				if(!input->ref_pic_order) //ref order
					fprintf(stdout,"%3d(I)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\n",
					FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time, "FRM",StatBitsPtr->prev_frame_bits,StatBitsPtr->prev_emulate_bits);   
			}
			else
			{      
				if(!input->ref_pic_order) // ref order
					fprintf(stdout,"%3d(P)  %3d %5d %7.4f %7.4f %7.4f %5d\t\t%s %8d %6d\n",
					FrameNum, pre_img_tr, pre_img_qp,snr->snr_y,snr->snr_u,snr->snr_v,pre_tmp_time,"FRM",StatBitsPtr->prev_frame_bits,StatBitsPtr->prev_emulate_bits);
			}
		}

		report_frame(snr,pre_tmp_time);

		if (input->output_dec_pic)
			write_prev_Pframe(img, p_out, img_prev);
	}

	// allocate memory for frame buffers
	if (img->number == 0) 
	{
		init_global_buffers(inp, img); 
	}

	for(i=0; i<img->max_mb_nr; i++)
	{
		mb_data[i].slice_nr = -1; 
	}

	for(i = 0 ; i < img->max_ref_num ; i++){
		p_mref[i] = p_ref_frm[i][0];        
		p_mcef[i][0] = p_ref_frm[i][1];
		p_mcef[i][1] = p_ref_frm[i][2];
	} 

	imgY_rec =  p_cur_frm[0];
	imgU_rec =  p_cur_frm[1];
	imgV_rec =  p_cur_frm[2];

	img->mv = img->mv_frm;
	refFrArr = refFrArr_frm;

	img->fw_refFrArr = img->fw_refFrArr_frm;
	img->bw_refFrArr = img->bw_refFrArr_frm;
}


void init_frame_buffer()
{
	int i;   
	for(i = 0 ; i < img->max_ref_num ; i++)
	{
		p_mref[i] = p_ref_frm[i][0];        
		p_mcef[i][0] = p_ref_frm[i][1];
		p_mcef[i][1] = p_ref_frm[i][2];
	}
}


/*
*************************************************************************
* Function:decodes one picture
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void picture_data(img_params *img)
{
	unsigned char *Buf;
	int startcodepos,length;
	int mb_width = img->PicWidthInMbs;
	int first_slice =1;
	Slice *currSlice = img->currentSlice;     
	int    ByteStartPosition;
	int    i;
	int    new_slice=0;
	Boolean   aec_mb_stuffing_bit;

	img->current_slice_nr = -1;				      
	currentbitoffset = currStream->frame_bitoffset;   
	currStream->frame_bitoffset = 0;               
	if ((Buf = (unsigned char*)calloc (MAX_CODED_FRAME_SIZE , sizeof(char))) == NULL) 
		no_mem_exit("GetAnnexbNALU: Buf");	 

	img->cod_counter=-1;

	while (img->current_mb_nr<img->PicSizeInMbs) // loop over macroblocks
	{
		if(img->current_mb_nr%mb_width ==0) // if the first MB is MB row
		{
			if(img->cod_counter<=0)
			{
				if(first_slice)
				{
					SliceHeader(temp_slice_buf,first_slice_startpos,first_slice_length);
					free(temp_slice_buf);
					img->current_slice_nr++;
					img->cod_counter = -1; 
					first_slice=0;
					new_slice=1;
				}
				else 
				{
					if(checkstartcode())
					{
						GetOneUnit(Buf,&startcodepos,&length);
						StatBitsPtr->curr_frame_bits += length;	
						SliceHeader(Buf,startcodepos,length);
						img->current_slice_nr++;
						img->cod_counter = -1; 
						new_slice=1;
					}
					else
						new_slice=0;
				}

				if(new_slice)
				{

					init_contexts(img);
					AEC_new_slice();
					ByteStartPosition = (currStream->frame_bitoffset)/8;

					for (i=0; i<1; i++)
					{
						img->currentSlice->partArr[i].readSyntaxElement = readSyntaxElement_AEC;
						img->currentSlice->partArr[i].bitstream = currStream ;
					}
					currStream = currSlice->partArr[0].bitstream;

					if ((currStream->frame_bitoffset)%8!=0)
						ByteStartPosition++;
					arideco_start_decoding (&img->currentSlice->partArr[0].de_AEC, currStream->streamBuffer, (ByteStartPosition), &(currStream->read_len));
				}
			}
		}  //decode slice header   
		mb_data[img->current_mb_nr].slice_nr = img->current_slice_nr;    

#if TRACE
		fprintf(p_trace,"\n*********** Pic: %i (I/P) MB: %i Slice: %i Type %d **********\n", img->tr, img->current_mb_nr, img->current_slice_nr, img->type);
#endif

		start_macroblock(img);
		read_one_macroblock(img);
		decode_one_macroblock(img);
		if(img->cod_counter<=0)  
			aec_mb_stuffing_bit = AEC_startcode_follows(img, 1);     
		img->current_mb_nr++;
	}

	free(Buf);

	DeblockFrame (img, imgY_rec, imgU_rec, imgV_rec);

	// padding
	image_padding(img, imgY_rec, imgU_rec, imgV_rec, IMG_PAD_SIZE);
}


/*
*************************************************************************
* Function:Prepare  frame buffer after frame decoding
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void frame_postprocessing(img_params *img)
{
	if((img->number)&&(img->type==I_IMG || img->type == P_IMG))
	{
		nextP_tr_frm = nextP_tr;
	}

	if (img->type==I_IMG || img->type == P_IMG) {
		img->PrevPicDistanceLsb = img->pic_distance;
		img->PicDistanceMsb = img->CurrPicDistanceMsb;
	}
}

/*
******************************************************************************
*  Function: Determine the MVD's value (1/4 pixel) is legal or not.
*  Input: 
*  Output: 
*  Return:   0: out of the legal mv range; 1: in the legal mv range
*  Attention:
*  Author: 
******************************************************************************
*/
void DecideMvRange()
{
	switch(level_id) {
	case 0x10:
		Min_V_MV = -512;
		Max_V_MV =  511;
		Min_H_MV = -8192;
		Max_H_MV =  8191;
		break;
	case 0x20:
		Min_V_MV = -1024;
		Max_V_MV =  1023;
		Min_H_MV = -8192;
		Max_H_MV =  8191;
		break;
	case 0x40:
		Min_V_MV = -2048;
		Max_V_MV =  2047;
		Min_H_MV = -8192;
		Max_H_MV =  8191;
		break;
	}
}
